<template>
  <div :class="{
    isAuto: isAuto,
  }">
    <el-upload class="upload-demo" v-bind="{
      'show-file-list': false,
      ...$attrs,
      drag: drag,
    }" :http-request="uploadBtn">
      <slot v-if="$slots.default" />
      <div class="el-upload__text" v-else-if="drag">
        拖拽文件到这里或 <em>点击上传</em>
      </div>
      <el-button type="" icon="Upload" v-else>{{ title }}</el-button>
    </el-upload>
    <LodingBox :loading="dataInfo.loading" loadingMsg="正在文件上传中...">
      <template #default v-if="fileFragmentation && fileMerge">
        <el-progress style="width: 100%;" :text-inside="true" :stroke-width="20"
          :percentage="Number((dataInfo.chunkIndex / dataInfo.chunkCount * 100).toFixed(0))" />
      </template>
    </LodingBox>
  </div>
</template>
<script setup lang="ts">
import { getCurrentInstance } from 'vue';
const { proxy } = getCurrentInstance() as any;
//获取父级数据
const props = withDefaults(
  defineProps<{
    data?: any;
    title?: string;
    fileFragmentation?: Function;//文件分片方法
    fileMerge?: Function;//文件合并方法
    chunkSize?: number,//分片小小
    type?: string,//文件类型
    isAuto?: boolean,//
    drag?: boolean,//是否拖拽上传
  }>(),
  {
    title: '文件上传',
    chunkSize: 1024 * 1024 * 2,//2M
  },
);
const dataInfo: any = reactive({
  loading: false,//是否加载
  chunkIndex: 1,//当前分片数量
  chunkCount: 1,//分片总数
});
const emit = defineEmits<{
  //fn为父组件引入子组件是定义的子组件事件属性，可随意定义
  (event: 'changeBtn', files: any, dataInfo: any, res: any): void;
}>();
const uploadBtn = (UploadRequestOptions: any) => {
  const _file = UploadRequestOptions.file;
  const _fileName = _file.name
  const files = {
    file: _file,
    fileName: _fileName.substring(0, _fileName.lastIndexOf('.')),//文件名称
    fileType: _fileName.substring(_fileName.lastIndexOf('.') + 1).toLowerCase(),//文件格式
    fileSize: _fileName,//文件大小
    fileImg: URL.createObjectURL(_file),//文件预览图
  };
  dataInfo.loading = true
  if (props.type) {
    var formData = new FormData();
    formData.append("file", _file);
    if (props.type === 'img') {
      proxy.$api.ExcuteUploadFile.UploadImageFile(formData)
        .then((res: any) => {
          emit('changeBtn', files, dataInfo, res);
        })
        .catch(() => {
          dataInfo.loading = false
        });
    } else if (props.type === 'all') {
      proxy.$api.ExcuteUploadFile.UploadSingleFile(formData)
        .then((res: any) => {
          emit('changeBtn', files, dataInfo, res);
        })
        .catch(() => {
          dataInfo.loading = false
        });
    }
  } else {
    emit('changeBtn', files, dataInfo, props.data);
  }
  //是否分片上传
  if (proxy.fileFragmentation && typeof props.fileFragmentation === 'function') {
    let chunks: any[] = sliceFile(_file)//获取分片数量
    dataInfo.chunkCount = chunks.length;
    dataInfo.chunkIndex = 1;
    uploadChunk_btn(files, chunks, 0, dataInfo.chunkCount)
  }
};
//分片上传
const uploadChunk_btn = (rawFile: any, chunks: any[], index: number = 0, chunkCount: number) => {
  if (proxy.fileFragmentation && typeof props.fileFragmentation === 'function') {
    //原始文件/分片数据/第几个分片/总分片
    let result: any = [
      props.fileFragmentation(rawFile, chunks[index], index + 1, chunkCount)
    ]
    Promise.all(result).then(() => {
      dataInfo.chunkIndex = index + 1
      if (index + 1 < chunkCount) {
        uploadChunk_btn(rawFile, chunks, index + 1, chunkCount)
      } else {
        if (proxy.fileMerge && typeof props.fileMerge === 'function') {
          //合并分片
          props.fileMerge(rawFile, dataInfo)
        } else {
          dataInfo.loading = false
        }
      }
    }).catch(() => {
      dataInfo.loading = false
    });;
  } else {
    dataInfo.loading = false
  }
};
//获取分片数量
const sliceFile = (file: any, chunkSize: number = props.chunkSize) => {
  let chunks = [];
  let start = 0;
  while (start < file.size) {
    const end = Math.min(start + chunkSize, file.size);
    // 使用 Blob.slice() 分片
    chunks.push(file.slice(start, end));
    start = end;
  }
  return chunks;
}


onMounted(() => { });
</script>
<style lang="scss">
.isAuto {
  .el-upload {
    width: 100%;

    .el-button {
      width: 100%;
    }
  }
}
</style>
